/*********************************
 * jsmud: JavaScript MUD Kernel  *
 *          Mojodo, Inc.         *
 *        Sean Middleditch       *
 * Copyright (C) 2005,2007,2008  *
 *      All rights reserved.     *
 *   See COPYING for licensing.  *
 *********************************/

/* ==== SYSTEM INCLUDES ==== */

#include <stdlib.h>

/* ==== LIBRARY INCLUDES ==== */

#include <sqlite3.h>
#include <zlib.h>

#define XP_UNIX 1
#define MOZILLA_1_8_BRANCH 1
#include <jsapi.h>
#undef XP_UNIX
#undef MOZILLA_1_8_BRANCH

/* ==== JSMUD HEADER ==== */

#include "jsmud.h"

/* ==== GLOBALS ==== */

Timer* timer_list = NULL;
double timer_game_scale = 0.0;

/* ==== FUNCTIONS ==== */

Timer* timer_new (double time, char gametime, jsval* callback)
{
	Timer* timer;

	if ((timer = (Timer*)malloc(sizeof(Timer))) == NULL)
		return NULL;
 
	timer->time_original = time;
	timer->time_remaining = time;
	timer->gametime = gametime;
	timer->callback = *callback;
	timer->next = timer_list;
	timer_list = timer;

	JS_AddRoot(js_context, &timer->callback);

	return timer;
}

double timer_next (void)
{
	double next;
	Timer* timer;

	if (timer_list == NULL)
		return 0.0;

	/* find timer with next soonest occurring time */
	next = timer_list->time_remaining;
	for (timer = timer_list->next; timer != NULL; timer = timer->next)
		if (timer->time_remaining < next)
			next = timer->time_remaining;

	return next;
}

void timer_free (Timer* timer)
{
	JS_RemoveRoot(js_context, &timer->callback);
	free(timer);
}

void timer_update (double elapsed)
{
	Timer* timer;
	Timer* last;
	Timer* next;
	jsval retval;
	JSBool ok;
	double game_elapsed = elapsed * timer_game_scale;

	/* iterate over all timers */
	for (timer = timer_list, last = NULL; timer != NULL; last = timer, timer = next) {
		next = timer->next;

		/* update time */
		if (timer->gametime)
			timer->time_remaining -= game_elapsed;
		else
			timer->time_remaining -= elapsed;

		/* elapsed time up? */
		while (timer->time_remaining <= 0.0) {
			/* if the callback fails or does not return true, remove timer */
			if (		(JS_CallFunction(js_context, js_global, JS_ValueToFunction(js_context, timer->callback), 0, NULL, &retval) == JS_FALSE) ||
					(JS_ValueToBoolean(js_context, retval, &ok) == JS_FALSE) ||
					(ok == JS_FALSE)
			) {
				/* fixup list */
				if (last == NULL)
					timer_list = timer->next;
				else
					last->next = timer->next;
				next = last ? last : timer_list;

				/* delete timer */
				timer_free(timer);
				break;
			} else {
				/* reset remaining timer */
				timer->time_remaining += timer->time_original;
			}
		}
	}
}

void timer_free_all (void)
{
	Timer* next;
	while (timer_list != NULL) {
		JS_RemoveRoot(js_context, &timer_list->callback);

		next = timer_list->next;
		free(timer_list);
		timer_list = next;
	}
}

/* vim: set tabstop=2 shiftwidth=2 ai: */
